#ifndef _UDP_SERVER_HPP_
#define _UDP_SERVER_HPP_
#include <memory>
#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <strings.h>
#include<functional>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Log.hpp"
#include "Mutex.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"

const static int gsockfd = -1;
const static std::string gdefaultip = "127.0.0.1";
const static uint16_t gdefaultport = 8080;

using namespace LogMudule;
using func_t = std::function<std::string(const std::string& st)> ;

class UdpServer
{
public:
    UdpServer(func_t func,uint16_t port = gdefaultport)
        : _sockfd(gsockfd),
        _addr(port),
        _func(func)
    {
    }

    void InitServer()
    {
        // 1.创建socket
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket:" << strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success:";
        // 2.填充网络信息，并且进行绑定
        /*struct sockaddr_in local;
        bzero(&local, sizeof(local));

        local.sin_family = AF_INET;
        local.sin_port = ::htons();    // 要被发送给对方的，即要发送到网络中
        local.sin_addr.s_addr = INADDR_ANY; // string ip->4bytes 2.network order*/
        

        // 2.1bind
        int n = ::bind(_sockfd, _addr.GetSockaddr_In(), _addr.LenSockaddr_in());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind " << strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success:";
    }

    void Start()
    {
        _isrunning = true;
        while (true)
        {
            // 收消息时，需要知道谁给我发的消息，利用socket标识另一端

            char inbuffer[1024];
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            /*InetAddr peer;//标识另一端
            socklen_t len = peer.LenSockaddr_in();*/
            ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
            if (n > 0)
            {
                //uint16_t peerport = ntohs(peer.sin_port);
                // std::string peerip = ::inet_ntoa(peer.sin_addr);//network->4bytes->string ip
                //std::string peerip = ::inet_ntoa(peer.sin_addr); // network->4bytes->string ip
                /*InetAddr cli(peer);
                inbuffer[n] = 0;

                std::string clientinfo = cli.GetIp() + ":" + std::to_string(cli.GetPort()) + "#" + inbuffer;
                LOG(LogLevel::DEBUG) << clientinfo;
                std::string Message = "echo# ";
                Message += inbuffer;*/
                inbuffer[n] = 0;
                std::string result = _func(inbuffer);
                ::sendto(_sockfd, result.c_str(), result.size(), 0, CONV(&peer), len);
            }
        }
    }

    ~UdpServer()
    {
        if(_sockfd>gsockfd)
        {
            ::close(_sockfd);
        }
    }

private:
    int _sockfd;
    InetAddr _addr;
    //uint16_t _port; // 服务器未来的端口号
    // std::string _ip;
    bool _isrunning = false;
    func_t _func;
};

#endif